package com.yanqu.road.server.gameplayer.module.activity.toyhouse;

import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ToyHouseCombTimesArgs;
import com.yanqu.road.entity.activity.toyhouse.ToyHouseBlock;
import com.yanqu.road.entity.activity.toyhouse.ToyHouseBlockData;
import com.yanqu.road.entity.activity.toyhouse.ToyHouseOrder;
import com.yanqu.road.entity.activity.toyhouse.ToyHouseOrderProg;
import com.yanqu.road.entity.activity.toyhouse.ToyHouseUserData;
import com.yanqu.road.entity.activity.toyhouse.config.ToyHouseCombConfig;
import com.yanqu.road.entity.activity.toyhouse.config.ToyHouseConfig;
import com.yanqu.road.entity.activity.toyhouse.config.ToyHouseOrderConfig;
import com.yanqu.road.entity.activity.toyhouse.eliminate.ToyHouseEliminateResult;
import com.yanqu.road.entity.activity.toyhouse.eliminate.ToyHouseEliminateRoundResult;
import com.yanqu.road.entity.activity.toyhouse.eliminate.ToyHouseEliminateStageResult;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eItemId;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.LogToyHouseCandy;
import com.yanqu.road.entity.log.LogToyHouseEliminate;
import com.yanqu.road.entity.log.LogToyHouseOrder;
import com.yanqu.road.logic.bussiness.activity.ToyHouseActivityBusiness;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.pb.activity.ToyHouseProto;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.VipMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.toyhouse.ToyHouseEliminateLogic;
import com.yanqu.road.server.manger.activity.toyhouse.ToyHouseMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.pb.ToyHousePb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ToyHouseModule extends GeneralModule {

    private RandomHelper randomHelper = new RandomHelper();

    private ToyHouseUserData userData = null;

    public ToyHouseModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = ToyHouseMgr.getActivityInfo();
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            userData = ToyHouseActivityBusiness.getToyHouseUserData(activityInfo.getActivityId(), getUserId());
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                ToyHouseActivityBusiness.addToyHouseUserData(userData);
            } else if (userData.isUpdateOption()) {
                ToyHouseActivityBusiness.updateToyHouseUserData(userData);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {
        initAndSyncData();
    }

    public ToyHouseUserData getUserData(ToyHouseConfig config) {
        // 判断初始化
        if (userData == null || userData.getActivityId() != config.getActivityInfo().getActivityId()) {
            initUserData();
        }
        ToyHouseUserData data = userData;
        // 体力判断
        if (data != null) {
            CalcPowerResult result = PowerHelper.calcPower(
                    data.getRecoveryTime() / 1000,
                    config.getEnergyRecTime() / 1000,
                    config.getEnergyRecCount(),
                    config.getMaxEnergy(),
                    data.getEnergy()
            );
            data.setEnergy(result.getCurPower());
            data.setRecoveryTime(result.getLastRecoverTime() * 1000L);
        }
        return data;
    }

    public void initAndSyncData() {
        ToyHouseConfig config = ToyHouseMgr.getConfig();
        if (config != null && ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            syncConfig(config);
            initUserData();
            updateToyCombTimes(config);
            syncUserData();
        }
    }

    public synchronized void initUserData() {
        // 系统解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.ToyHouse.getValue())) {
            return;
        }
        // 判断配置
        ToyHouseConfig config = ToyHouseMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }
        // 是否已有数据
        if (userData != null && userData.getActivityId() == config.getActivityInfo().getActivityId()) {
            return;
        }

        // 开始初始化数据
        ToyHouseUserData tmpUserData = new ToyHouseUserData();
        tmpUserData.setActivityId(config.getActivityInfo().getActivityId());
        tmpUserData.setUserId(getUserId());
        tmpUserData.setScore(0);
        tmpUserData.setCandyCount(0);
        tmpUserData.setEnergy(config.getMaxEnergy());
        tmpUserData.setRecoveryTime(System.currentTimeMillis());
        tmpUserData.setGuideIndex(0);
        tmpUserData.setBlockDataMap(new ConcurrentHashMap<>());
        tmpUserData.setOrderMap(new ConcurrentHashMap<>());
        tmpUserData.setToyProp(new Property());
        tmpUserData.setInsertOption();

        // 单倍格子
        int guideIndex = tmpUserData.getGuideIndex();
        int[] initBlock1 = config.getInitBlock();
        int[][] blockList1 = new int[ToyHouseEliminateLogic.MAX_HEIGHT][ToyHouseEliminateLogic.MAX_WIDTH];
        for (int y = 0; y < blockList1.length; y++) {
            for (int x = 0; x < blockList1[y].length; x++) {
                blockList1[y][x] = initBlock1[guideIndex++];
            }
        }
        tmpUserData.getBlockDataMap().put(1, new ToyHouseBlockData(1, blockList1));
        tmpUserData.setGuideIndex(guideIndex);

        // 八倍格子
        int index = 0;
        int[] initBlock8 = config.getInitBlock8();
        int[][] blockList8 = new int[ToyHouseEliminateLogic.MAX_HEIGHT][ToyHouseEliminateLogic.MAX_WIDTH];
        for (int y = 0; y < blockList8.length; y++) {
            for (int x = 0; x < blockList8[y].length; x++) {
                blockList8[y][x] = initBlock8[index++];
            }
        }
        tmpUserData.getBlockDataMap().put(8, new ToyHouseBlockData(8, blockList8));

        // 单倍订单
        tmpUserData.getOrderMap().put(1, ToyHouseMgr.getNewOrder(config.getOrderConfigMap().get(config.getGuideOrderId())));

        // 八倍订单
        tmpUserData.getOrderMap().put(8, ToyHouseMgr.getRandomNewOrder(config, randomHelper, 8));

        // 初始订单加进度
        Map<Integer, ToyHouseOrderProg> progMap = tmpUserData.getOrderMap().get(1).getProgMap();
        Property property = PropertyHelper.parseStringToProperty(config.getInitOrderProgress());
        for (Map.Entry<Integer, BigInteger> entry : property.getGoods().entrySet()) {
            int toyId = entry.getKey();
            int count = entry.getValue().intValue();
            if (progMap.containsKey(toyId)) {
                progMap.get(toyId).setCur(count);
            }
        }
        tmpUserData.setUpdateOption();

        // 替换
        userData = tmpUserData;
    }

    public void syncConfig(ToyHouseConfig config) {
        player.sendPacket(ClientProtocol.U_TOY_HOUSE_SYNC_CONFIG, ToyHousePb.parseToyHouseSyncConfigRespMsg(config, player.getLanguage()));
    }

    public void syncUserData() {
        if (userData != null) {
            player.sendPacket(ClientProtocol.U_TOY_HOUSE_SYNC_USER_DATA, ToyHousePb.parseToyHouseSyncUserDataRespMsg(userData));
        }
    }

    public int syncGameData(ToyHouseConfig config, int multi) {
        // 玩家数据
        if (getUserData(config) == null) {
            return GameErrorCode.E_TOY_HOUSE_NO_UNLOCK;
        }

        // 多倍判断
        if (!config.getMultiUnlockMap().containsKey(multi)) {
            return GameErrorCode.E_TOY_HOUSE_NO_MULTI;
        }

        // 同步
        ToyHouseProto.ToyHouseGetGameDataRespMsg.Builder builder = ToyHouseProto.ToyHouseGetGameDataRespMsg.newBuilder();
        builder.setRet(0);
        builder.setGameData(ToyHousePb.parseToyHouseGameDataMsg(userData, multi));
        player.sendPacket(ClientProtocol.U_TOY_HOUSE_GET_GAME_DATA, builder);
        return 0;
    }

    public int useEnergyItem(ToyHouseConfig config, int count) {

        // 玩家数据
        if (getUserData(config) == null) {
            return GameErrorCode.E_TOY_HOUSE_NO_UNLOCK;
        }

        // 数量校验
        if (count < 1 || count > 99999) {
            return GameErrorCode.E_BAG_USE_GOODS_COUNT_LESS_ONE;
        }

        // 获取配置
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(config.getEnergyId());
        if (goodsInfo == null) {
            return GameErrorCode.E_GOODS_NO_EXIST;
        }
        int addNum = goodsInfo.getParamList().get(0).intValue() * count;

        // 扣道具
        Property consume = new Property();
        consume.addProperty(config.getEnergyId(), BigInteger.valueOf(count));
        if (!player.getModule(CurrencyModule.class).removeCurrency(consume, eLogMoneyType.ToyHouse, eLogMoneyType.ToyHouseUseEnergy)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        // 加体力
        userData.setEnergy(addNum + userData.getEnergy());
        if (userData.getEnergy() > config.getMaxEnergy()) {
            userData.setRecoveryTime(System.currentTimeMillis());
        }

        // 返回
        ToyHouseProto.ToyHouseUseEnergyItemRespMsg.Builder builder = ToyHouseProto.ToyHouseUseEnergyItemRespMsg.newBuilder();
        builder.setRet(0);
        builder.setEnergyMsg(ToyHousePb.parseToyHouseEnergyMsg(userData));
        player.sendPacket(ClientProtocol.U_TOY_HOUSE_USE_ENERGY_ITEM, builder);
        return 0;
    }

    public int eliminateBlock(ToyHouseConfig config, int multi,
                              int fromX, int fromY, int toX, int toY) {

        // 玩家数据
        if (getUserData(config) == null) {
            return GameErrorCode.E_TOY_HOUSE_NO_UNLOCK;
        }

        // 多倍判断
        List<Integer> unlockConfig = config.getMultiUnlockMap().get(multi);
        if (unlockConfig == null) {
            return GameErrorCode.E_TOY_HOUSE_NO_MULTI;
        }
        if ((unlockConfig.get(0) == -1 || userData.getScore() < unlockConfig.get(0))
                && (unlockConfig.get(1) == -1 || VipMgr.getVipLv(player.getUserInfo().getVipExp()) < unlockConfig.get(1))) {
            return GameErrorCode.E_TOY_HOUSE_NO_UNLOCK_MULTI;
        }

        // 拿体力配置
        int costEnergy = config.getEnergyCostMap().get(multi);
        if (userData.getEnergy() < costEnergy) {
            return GameErrorCode.E_TOY_HOUSE_ENERGY_NO_ENOUGH;
        }

        // 日志
        int logBeforeEnergy = userData.getEnergy();
        List<LogToyHouseOrder> logToyHouseOrderList = new ArrayList<>();
        Property logBoomUse1 = new Property();
        int logCount1 = 0;
        Property logBombCreate1 = new Property();
        long logScore1 = 0;
        int logCount2 = 0;
        Property logBombCreate2 = new Property();
        long logScore2 = 0;

        // 消除
        ToyHouseEliminateResult result = ToyHouseEliminateLogic.eliminateBlock(randomHelper, config, userData, multi, fromX, fromY, toX, toY);

        ToyHouseProto.ToyHouseEliminateRespMsg.Builder builder = ToyHouseProto.ToyHouseEliminateRespMsg.newBuilder();
        builder.setRet(result.getRet());

        // 消除失败返回
        if (result.getRet() != 0) {
            return result.getRet();
        }

        // 扣体力
        reduceEnergy(config, costEnergy);

        // 处理结果
        long totalScore = 0;
        List<ToyHouseOrder> finishOrderList = new ArrayList<>();
        int round = 0;
        for (ToyHouseEliminateRoundResult roundResult : result.getRoundResultList()) {
            round++;
            ToyHouseProto.ToyHouseEliminateRoundMsg.Builder roundMsg = ToyHousePb.parseToyHouseEliminateRoundMsg(roundResult);
            builder.addRoundMsgList(roundMsg);

            for (ToyHouseEliminateStageResult stageResult : roundResult.getStageResultList()) {
                for (ToyHouseBlock drinkBlock : stageResult.getBlockList()) {
                    totalScore += drinkBlock.getScore();

                    // 日志
                    if (ToyHouseEliminateLogic.isBomb(drinkBlock.getC())) {
                        logBoomUse1.addProperty(drinkBlock.getC(), BigInteger.ONE);
                    }
                    if (round == 1) {
                        logScore1 += drinkBlock.getScore();
                    } else {
                        logScore2 += drinkBlock.getScore();
                    }
                }
                // 日志
                if (round == 1) {
                    logCount1 += stageResult.getBlockList().size();
                } else {
                    logCount2 += stageResult.getBlockList().size();
                }
            }
            if (roundResult.getFinishOrder() != null) {
                finishOrderList.add(roundResult.getFinishOrder());
            }
            // 日志
            for (ToyHouseBlock bomb : roundResult.getCreateBomb()) {
                if (round == 1) {
                    logBombCreate1.addProperty(bomb.getC(), BigInteger.ONE);
                } else {
                    logBombCreate2.addProperty(bomb.getC(), BigInteger.ONE);
                }
            }
        }

        // 组装积分奖励
        Property property = new Property();
        property.addProperty(config.getScoreId(), BigInteger.valueOf(totalScore));

        // 组装订单奖励
        Property orderScoreProp = new Property();
        Property toyProp = new Property();
        for (ToyHouseOrder order : finishOrderList) {
            ToyHouseOrderConfig orderConfig = config.getOrderConfigMap().get(order.getoId());
            int score = orderConfig.getScore();
            orderScoreProp.addProperty(config.getScoreId(), BigInteger.valueOf(score));
            toyProp.addProperty(order.getoId(), BigInteger.ONE);

            // 日志
            logToyHouseOrderList.add(new LogToyHouseOrder(config.getActivityInfo().getActivityId(), getUserId(), order.getoId(), PropertyHelper.parsePropertyToString(orderScoreProp)));
        }

        // 设置结果
        userData.setGuideIndex(result.getGuideIndex());
        userData.getBlockDataMap().put(multi,
                new ToyHouseBlockData(multi, ToyHouseMgr.getCopyBlockList(result.getRoundResultList().get(result.getRoundResultList().size() - 1).getBlockList())));
        userData.getOrderMap().put(multi, result.getCurOrder());
        userData.setScore(userData.getScore() + totalScore + orderScoreProp.getCountByGoodsId(config.getScoreId()).longValue());

        // 加奖励
        player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.ToyHouse, eLogMoneyType.ToyHouseEliminate); // 消除积分
        player.getModule(CurrencyModule.class).addCurrency(orderScoreProp, eLogMoneyType.ToyHouse, eLogMoneyType.ToyHouseFinishOrder); // 订单积分
        userData.getToyProp().addProperty(toyProp); // 订单玩具

        // 榜单
        player.notifyListener(eGamePlayerEventType.ToyHouseCrossScoreRank.getValue(), userData.getScore());

        // 组合成就次数
        updateToyCombTimes(config);

        // 返回
        builder.setGameData(ToyHousePb.parseToyHouseGameDataMsg(userData, multi));
        player.sendPacket(ClientProtocol.U_TOY_HOUSE_ELIMINATE, builder);

        // 日志
        for (LogToyHouseOrder logToyHouseOrder : logToyHouseOrderList) {
            LogMgr.addLogToyHouseOrder(logToyHouseOrder);
        }
        LogMgr.addLogToyHouseEliminate(new LogToyHouseEliminate(
                config.getActivityInfo().getActivityId(),
                getUserId(),
                multi,
                logBeforeEnergy,
                costEnergy,
                PropertyHelper.parsePropertyToString(logBoomUse1),
                logCount1,
                PropertyHelper.parsePropertyToString(logBombCreate1),
                logScore1,
                result.getRoundResultList().size(),
                logCount2,
                PropertyHelper.parsePropertyToString(logBombCreate2),
                logScore2
        ));

        return 0;
    }

    private boolean reduceEnergy(ToyHouseConfig config, int count) {
        getUserData(config);

        if (userData.getEnergy() < count) {
            return false;
        }

        int maxEnergy = config.getMaxEnergy();
        boolean aboveMaxBefore = userData.getEnergy() >= maxEnergy;

        userData.setEnergy(userData.getEnergy() - count);

        if (aboveMaxBefore) {
            userData.setRecoveryTime(System.currentTimeMillis());
        }
        return true;
    }

    private void updateToyCombTimes(ToyHouseConfig config) {
        if (userData == null) {
            return;
        }

        Property toyProp = userData.getToyProp();

        // 遍历配置中的组合
        for (ToyHouseCombConfig combConfig : config.getCombConfigMap().values()) {
            long minTimes = Integer.MAX_VALUE;
            for (Map.Entry<Integer, BigInteger> entry : combConfig.getElementProp().getGoods().entrySet()) {
                // 当前玩具满足次数 = 当前玩具数量 / 每次组合所需数量
                long tmpTimes = toyProp.getCountByGoodsId(entry.getKey()).longValue() / entry.getValue().longValue();
                // 取最小次数
                minTimes = Math.min(minTimes, tmpTimes);
                if (minTimes == 0) {
                    break;
                }
            }
            player.notifyListener(eGamePlayerEventType.ToyHouseCombTimes.getValue(), new ToyHouseCombTimesArgs(combConfig.getCombId(), minTimes));
        }
    }

    public void addCandy(int candyId, long count, eLogMoneyType son) {
        ToyHouseConfig config = ToyHouseMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            LogMgr.addLogToyHouseCandy(new LogToyHouseCandy(
                    getUserId(),
                    config == null ? 0 : config.getActivityInfo().getActivityId(),
                    son.getValue(),
                    candyId,
                    count,
                    1,
                    -1)); // 没活动
            return;
        }

        getUserData(config);
        if (userData == null) {
            LogMgr.addLogToyHouseCandy(new LogToyHouseCandy(
                    getUserId(),
                    config.getActivityInfo().getActivityId(),
                    son.getValue(),
                    candyId,
                    count,
                    2,
                    -1)); // 没解锁
            return;
        }

        // 修改数据
        userData.setCandyCount(userData.getCandyCount() + count);
        player.notifyListener(eGamePlayerEventType.ToyHouseCandyCount.getValue(), userData.getCandyCount());

        // 同步糖果子数量
        syncUserData();

        LogMgr.addLogToyHouseCandy(new LogToyHouseCandy(
                getUserId(),
                config.getActivityInfo().getActivityId(),
                son.getValue(),
                candyId,
                count,
                0,
                userData.getCandyCount())); // 成功
    }
}
